package io.jnet.client;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousChannelGroup;
import java.nio.channels.AsynchronousSocketChannel;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import com.jfireframework.baseutil.exception.JustThrowException;
import io.jnet.client.api.AioClient;
import io.jnet.client.api.ClientChannelContext;
import io.jnet.client.api.ClientChannelContextBuilder;
import io.jnet.client.api.ClientListener;
import io.jnet.client.clientchannelcontext.SimpleClientChannelContext;
import io.jnet.client.util.ClientChannelContextConfig;

public class BufferAioClient implements AioClient
{
    private static final int                  connectTimeout = 10;
    private final AsynchronousChannelGroup    channelGroup;
    private final String                      serverIp;
    private final int                         port;
    private final ClientListener              clientListener;
    private final ClientChannelContextBuilder clientChannelContextBuilder;
    private ClientChannelContext              clientChannelContext;
    
    public BufferAioClient(ClientChannelContextBuilder clientChannelContextBuilder, AsynchronousChannelGroup channelGroup, String serverIp, int port, ClientListener clientListener)
    {
        this.channelGroup = channelGroup;
        this.serverIp = serverIp;
        this.port = port;
        this.clientListener = clientListener;
        this.clientChannelContextBuilder = clientChannelContextBuilder;
    }
    
    @Override
    public void connect()
    {
        try
        {
            AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open(channelGroup);
            socketChannel.connect(new InetSocketAddress(serverIp, port)).get(connectTimeout, TimeUnit.SECONDS);
            ClientChannelContextConfig config = clientChannelContextBuilder.onConnect(socketChannel);
            clientChannelContext = new SimpleClientChannelContext(config.getMaxMerge(), config.getBufStorage(), config.getOutProcessors(), socketChannel, clientListener, config.getInProcessors(), config.getFrameDecodec());
            clientChannelContext.registerRead();
        }
        catch (IOException | InterruptedException | ExecutionException | TimeoutException e)
        {
            throw new JustThrowException(e);
        }
    }
    
    @Override
    public void close()
    {
        clientChannelContext.close();
        clientChannelContext = null;
    }
    
    @Override
    public void write(Object packet) throws Throwable
    {
        clientChannelContext.write(packet, 0);
    }
    
}
